package org.kgduyjj.toolkit;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.Optional;
import java.util.regex.Pattern;

import org.kgduyjj.toolkit.text.Convert;
import org.kgduyjj.toolkit.util.DateUtils;
import org.kgduyjj.toolkit.util.DateUtils.Patterns;
import org.kgduyjj.toolkit.util.ObjectUtils;
import org.kgduyjj.toolkit.util.RandomUtil;
import org.kgduyjj.toolkit.util.StringUtils;

/**
 * 通用工具类
 * 
 * @author Kgduyjj
 *
 */
public class Func {
    /** 空字符串 */
    public static final String EMPTY = "";
    /** 数值零 INT */
    public static final int ZERO_INT = 0;
    /** 数值零 DOUBLE */
    public static final double ZERO_DOUBLE = 0;
    /** 数值保留小数位数 */
    protected static final int DEFAULT_SCALE = 2;
    /** 1年的小时数 */
    protected static final int HOUR_OF_YEAR = 8760;
    /** 1年的分钟数 */
    protected static final int MINUTE_OF_YEAR = 525600;
    /** 1天的小时数 */
    protected static final int HOUR_OF_DAY = 24;
    /** 1天的分钟数 */
    protected static final int MINUTE_OF_DAY = 1440;
    /** 1小时的分钟数 */
    protected static final int MINUTE_OF_HOUR = 60;
    /** 时间进制单位 从大到小分别为<code>【年 > 天 > 小时 > 分钟】</code> */
    protected static final String[] TIME_UNIT = { "年", "天", "小时", "分钟" };
    /** 字符串标识{@code null} */
    protected static final String STRING_NULL = "null";
    protected static final Pattern NUMBER_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");

    /**
     * 分钟格式化
     * 
     * @param minute
     * @return
     */
    public static String minuteFormat(Double minuteCount) {
        if (ObjectUtils.isNull(minuteCount)) {
            return EMPTY;
        }
//        int years = minuteCount.intValue() / MINUTE_OF_YEAR;
//        int days = (minuteCount.intValue() - (years * MINUTE_OF_YEAR)) / (MINUTE_OF_DAY);
//        int hours = (minuteCount.intValue() - (years * MINUTE_OF_YEAR) - (days * MINUTE_OF_DAY)) / MINUTE_OF_HOUR;
//        int calculated = (years * MINUTE_OF_YEAR) + (days * MINUTE_OF_DAY) + (hours * MINUTE_OF_HOUR);
//        double minute = Arith.sub(minuteCount, Double.valueOf(calculated));
//        StringBuilder result = new StringBuilder();
//        // 若年数不为0
//        if (ZERO_INT != years) {
//            result.append(years).append(TIME_UNIT[0]);
//        }
//        // 若天数不为0
//        if (ZERO_INT != days) {
//            result.append(days).append(TIME_UNIT[1]);
//        }
//        // 若小时数不为0
//        if (ZERO_INT != hours) {
//            result.append(hours).append(TIME_UNIT[2]);
//        }
//        // 分钟数保留两位
//        result.append(Arith.round(minute, 2)).append(TIME_UNIT[3]);
//        return result.toString();
        return hourFormat(Arith.div(minuteCount, MINUTE_OF_HOUR, DEFAULT_SCALE));
    }

    /**
     * 时间转换器，把小时数转换为指定格式的数据
     * 
     * <pre>
     * Y年D天H小时
     * </pre>
     * 
     * @param hourCount
     * @return
     */
    public static String hourFormat(Double hourCount) {
        if (ObjectUtils.isNull(hourCount)) {
            return EMPTY;
        }
        int years = hourCount.intValue() / HOUR_OF_YEAR;
        int days = (hourCount.intValue() - (years * HOUR_OF_YEAR)) / HOUR_OF_DAY;
        double hours = Arith.sub(hourCount, Double.valueOf((years * HOUR_OF_YEAR) + (days * HOUR_OF_DAY)));
        StringBuilder result = new StringBuilder();
        //
        if (ZERO_INT != years) {
            result.append(years).append(TIME_UNIT[0]);
        }
        if (ZERO_INT != years && ZERO_INT == days) {
            result.append(ZERO_INT).append(TIME_UNIT[1]);
        } else if (ZERO_INT != days) {
            result.append(days).append(TIME_UNIT[1]);
        }
        result.append(Arith.round(hours, DEFAULT_SCALE)).append(TIME_UNIT[2]);
        return result.toString();
    }

    /**
     * 在转换前对于输入值进行一次校验，若匹配则返回{@code null}
     * 
     * <pre>
     * 1, 不为空白或{@code null}
     * 2, 不为[null] [Null] [NULL]等值
     * </pre>
     * 
     * @param text
     * @return
     */
    protected static String requireNonNull(String text) {
        if (StringUtils.isBlank(text)) {
            return null;
        }
        if (STRING_NULL.contains(text.toLowerCase())) {
            return null;
        }
        return text;

    }

    /**
     * 在转换前对于输入值进行一次校验，若匹配则返回{@code null}
     * 
     * <pre>
     * 1, 不为空白或{@code null}
     * 2, 不为[null] [Null] [NULL]等值
     * 3, 不为数值格式
     * </pre>
     * 
     * @param text
     * @return
     */
    protected static String requireNumber(String text) {
        if (StringUtils.isBlank(text)) {
            return null;
        }
        if (STRING_NULL.contains(text.toLowerCase())) {
            return null;
        }
        if (!NUMBER_PATTERN.matcher(text).matches()) {
            return null;
        }
        return text;
    }

    /**
     * 把文本转换为{@link BigDecimal}
     * 
     * @param text
     * @return
     */
    protected static BigDecimal parseBigDecimal(String text) {
        if (StringUtils.isBlank(requireNumber(text))) {
            return null;
        }
        return new BigDecimal(text);
    }

    /**
     * 把数据转换为Integer
     * 
     * @param datavalue
     * @return
     */
    public static Integer parseInt(String datavalue) {
        return Optional.ofNullable(parseBigDecimal(datavalue)).map(BigDecimal::intValue).orElse(null);
    }

    /**
     * 把数据转换为Integer
     * 
     * @param datavalue
     * @return
     */
    public static Integer parseInt(Double datavalue) {
        return Convert.toInt(datavalue);
    }

    /**
     * 把字符串数据转换为2位小数的数据
     * 
     * @param datavalue
     * @return
     */
    public static Double parseDouble(String datavalue) {
        return Optional.ofNullable(parseBigDecimal(datavalue)).map(BigDecimal::doubleValue).orElse(null);
    }

    /**
     * 转换为日期
     * 
     * @param rectime
     * @return
     */
    public static Date parseDate(String rectime) {
        rectime = requireNonNull(rectime);
        try {
            return DateUtils.parse(rectime, Patterns.DATETIME);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 校验数据不为空且不为0
     * 
     * @param datavalue
     * @return
     */
    public static boolean notZeroOrNull(String datavalue) {
        Integer dv = parseInt(datavalue);
        return ObjectUtils.isNull(dv) ? false : (ZERO_INT != dv.intValue());
    }

    /**
     * 数据值大于0
     * 
     * @param datavalue
     * @return
     */
    public static boolean laggerZero(String datavalue) {
        Double dv = parseDouble(datavalue);
        return ObjectUtils.isNull(dv) ? false : (dv.doubleValue() > ZERO_DOUBLE);
    }

    /**
     * 计算百分比
     * 
     * <pre>
     * eg. 32/100 = 32[%]
     * </pre>
     * 
     * @param value
     * @param total
     * @return
     */
    public static Double percentageRate(Double value, Double total) {
        Double pRate = percentageDecimal(value, total);
        if (ObjectUtils.isNull(pRate)) {
            return null;
        }
        return Arith.mul(pRate, 100);
    }

    /**
     * 计算百分比
     * 
     * @param count
     * @param total
     * @return
     */
    public static Double percentageDecimal(Double count, Double total) {
        if (ObjectUtils.anyNull(count, total)) {
            return null;
        }
        return Arith.div(count, total, 4);
    }

    /**
     * 生成数据随机值
     * 
     * @param min
     * @param max
     * @return
     */
    public static String randomDoubleString(double min, double max) {
        return String.valueOf(randomDouble(min, max));
    }

    /**
     * 生成数据随机值
     * 
     * @param min
     * @param max
     * @return
     */
    public static Double randomDouble(double min, double max) {
        return RandomUtil.randomDouble(min, max, 2, RoundingMode.HALF_UP);
    }

    /**
     * 对于数值进行四舍五入保留两位小数
     * 
     * @param value
     * @return
     */
    public static Double round(Double value) {
        if (ObjectUtils.isNull(value)) {
            return Arith.ZERO;
        }
        return Arith.round(value, 2);
    }

    /**
     * 日志构建块
     * 
     * @param msg
     * @return
     */
    public static String logBlock(Object msg) {
        if (msg == null) {
            msg = "";
        }
        return "[" + msg.toString() + "]";
    }
}
